﻿using PlutoStudio.Net.Messages;
using PlutoStudio.Net.Processors.Attributes;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Reflection;
using System.Text;

namespace PlutoStudio.Net.Processors
{
    internal static class ActionSelector
    {
        private static readonly ConcurrentDictionary<Type, ConcurrentDictionary<ushort, ActionDispatcher>> CachedDispatchers;

        static ActionSelector()
        {
            CachedDispatchers = new ConcurrentDictionary<Type, ConcurrentDictionary<ushort, ActionDispatcher>>();
        }

        public static void AddActions(Type type, ConcurrentDictionary<ushort, ActionDispatcher> actions)
        {
            CachedDispatchers.TryAdd(type,actions);
        }

        public static ActionDispatcher GetAtion<T>(this T processor) where T : MessageProcessorBase
        {
            var type = processor.GetType();
            if (!CachedDispatchers.ContainsKey(type))
            {
                CachedDispatchers.TryAdd(type, GenerateActionDispatcher(type));
            }
            if (!CachedDispatchers[type].ContainsKey(processor.Message.Code))
            {
                if (processor.Context.ResponseError)
                {
                    var message = new Message(processor.Message.Flag, processor.Message.Code, (UInt16)StatusCode.NotImplemented);
                    message.SetData("指定的方法不存在！");
                    processor.Context.Send(message); 
                }
                throw new NotImplementedException("指定的方法不存在");
            }
            return CachedDispatchers[type][processor.Message.Code];
        }


        private static ConcurrentDictionary<ushort, ActionDispatcher> GenerateActionDispatcher(Type type)
        {
            var result = new ConcurrentDictionary<ushort, ActionDispatcher>();
            var methods = type.GetMethods();
            foreach (var item in methods)
            {
                var attributes = item.GetCustomAttributes(typeof(MessageCodeAttribute), true);
                if (attributes.Length == 0)
                {
                    continue;
                }
                foreach (MessageCodeAttribute attirbute in attributes)
                {
                    result.TryAdd(attirbute.Code, new ActionDispatcher(item));
                }

            }
            return result;
        }
    }

    internal class ActionDispatcher
    {
        public ActionDispatcher(MethodInfo method)
        {
            this.Method = method;
            var processorType = method.DeclaringType;
            AuthorizationFilter = method.GetCustomAttributes(typeof(AuthorizationAttribute), true).Cast<AuthorizationAttribute>().ToArray();
            DecryptionFilter = method.GetCustomAttributes(typeof(DecryptionAttribute), true).Cast<DecryptionAttribute>().FirstOrDefault();
            EncryptionFilter = method.GetCustomAttributes(typeof(EncryptionAttribute), true).Cast<EncryptionAttribute>().FirstOrDefault();
            ExceptionFilter = method.GetCustomAttributes(typeof(HandlerErrorAttribute), true).Cast<HandlerErrorAttribute>().ToArray();
            if (AuthorizationFilter.Length == 0)
            {
                AuthorizationFilter = processorType.GetCustomAttributes(typeof(AuthorizationAttribute), true).Cast<AuthorizationAttribute>().ToArray();
            }
            if (DecryptionFilter == null)
            {
                DecryptionFilter = processorType.GetCustomAttributes(typeof(DecryptionAttribute), true).Cast<DecryptionAttribute>().FirstOrDefault();
            }
            if (EncryptionFilter == null)
            {
                EncryptionFilter = processorType.GetCustomAttributes(typeof(EncryptionAttribute), true).Cast<EncryptionAttribute>().FirstOrDefault();
            }
            if (ExceptionFilter.Length == 0)
            {
                ExceptionFilter = processorType.GetCustomAttributes(typeof(HandlerErrorAttribute), true).Cast<HandlerErrorAttribute>().ToArray();
            }
        }

        public IAuthorizationFilter[] AuthorizationFilter { get; set; }

        public IExceptionFilter[] ExceptionFilter { get; set; }

        public IDecryptionFilter DecryptionFilter { get; set; }

        public IEncryptionFilter EncryptionFilter { get; set; }

        public MethodInfo Method { get; private set; }

        public void ExecuteAction(MessageProcessorBase process)
        {
            if (DecryptionFilter != null)
            {
                DecryptionFilter.OnDecryptValue(process);
            }
            if (AuthorizationFilter != null)
            {
                foreach (var item in AuthorizationFilter)
                {
                    if (!item.OnAuthorization(process))
                    {
                        return;
                    }
                }
            }
            try
            {
                var content = Encoding.UTF8.GetString(process.Message.Data);
                object[] parameters;
                try
                {
                    parameters = GetParameters(content);
                }
                catch (Exception ex)
                {
                    if (process.Context.ResponseError)
                    {
                        var message = new Message(process.Message.Flag, process.Message.Code, (UInt16)StatusCode.BadRequest);
                        message.SetData("请求失败，参数错误！");
                        process.Context.Send(message);

                    }
                    TraceHelper.Helper.TraceError("填充处理器执行参数发生异常：\r\n    处理器:{0}；方法：{1}；参数对象：{2}。 \r\n   {3}",process.GetType().Name,this.Method.Name,content,  ex.ToString());
                    return;
                }
                var result = Method.Invoke(process, parameters) as ActionResult;
                if (result==null)
                {
                    return;
                }
                result.ExecuteResult(process,EncryptionFilter);
            }
            catch (Exception ex)
            {
                TraceHelper.Helper.TraceError("处理消息发生异常：\r\n    处理器:{0}；方法：{1}。 \r\n   {2}", process.GetType().Name, this.Method.Name, ex.ToString());
                if (ExceptionFilter != null)
                {
                    foreach (var item in ExceptionFilter)
                    {
                        item.OnException(process, ex);
                    }
                }
            }
        }

        private object[] GetParameters(string content)
        {
            var parameters = this.Method.GetParameters();
            if (parameters.Length == 0)//无参数直接返回
            {
                return new object[] { };
            }

            if (parameters.Length == 1 && content[0] != '{' && content[0] != '[')
            {
                var parameter = parameters.First();
                return new object[] { Convert.ChangeType(content, parameter.ParameterType) };
            }
            var dict = Newtonsoft.Json.JsonConvert.DeserializeObject(content) as Newtonsoft.Json.Linq.JContainer;
            if (parameters.Length == 1)
            {
                var parameter = parameters.First();
                if (dict is Newtonsoft.Json.Linq.JObject &&  dict[parameter.Name] != null)
                {
                    return new object[] { dict[parameter.Name].ToObject(parameter.ParameterType) };
                }
                return new object[] { dict.ToObject(parameter.ParameterType) };
            }
            else
            {
                var result = new ArrayList();
                foreach (var item in parameters)
                {
                    result.Add(dict[item.Name].ToObject(item.ParameterType));
                }
                return result.ToArray();
            }
        }
    }
}
